/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.testis.nicmodule.core;

import org.testis.utils.TerminalApplicationExecutor;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.util.Enumeration;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.ArrayList;
import java.util.List;

/**Concrete Implementor side for linux os
 *
 * @author alperb
 */
public class NetworkOSLinux extends NetworkOS {

    /**
     * enable interface parameters concrete implementation method
     * uses ifconfig for enabling
     * @param String iPath for interface to be enabled/disabled
     * @param boolean enabled true for up false for down
     * @return true/false to represent succes or fail
     */
    public boolean enableInterface(String iPath,
            boolean enabled) {
        try {

            if ((iPath == null) || (iPath.trim().equals(""))) {
                throw new NicModuleException(
                        NicModuleExceptionType.IFACENAMENULL,
                        "NetworkOSLinux:enableInterface called with null as interface and enabled parameeter as "
                        + Boolean.toString(enabled));
            }

            StringBuffer cmd = new StringBuffer();
            cmd.append("ifconfig ");
            cmd.append(iPath);
            cmd.append("\t");



            if (enabled) {
                cmd.append(" up ");

            } else {
                cmd.append("down ");
            }

            TerminalApplicationExecutor executor =
                    new TerminalApplicationExecutor(cmd.toString(),
                    "");
            Integer exitVal = executor.runExec();

            String outputStr = executor.getOutputString();
            String errStr = executor.getErrorString();
            if (exitVal == 0) {
                return true;
            } else {
                throw new NicModuleException(NicModuleExceptionType.EXECUTIONERR,
                        "NetworkOSLinux:enableInterface execution error"
                        + errStr);
            }
        } catch (Exception ex) {
            throw new NicModuleException(NicModuleExceptionType.UNEXPLAINED,
                    "NetworkOSLinux:enableInterface exception "
                    + ex.getMessage().toString());
        }
    }

    /**
     * set interface configuration parameters method
     * set configuratin by usinf ifconfig command
     * @param all needed parameters in String form
     * @return true/false to represent succes or fail
     */
    public boolean setInterfaceConfiguration(String iPath,
            String ip,
            String gateWay,
            String dns,
            String subnetMask,
            Boolean fromDhcp,
            String messageId) {

        try {

            if (fromDhcp) {//implement for linux
                return setToDhcp(iPath);
            }
            if ((iPath == null) || (iPath.trim().equals(""))) {
                throw new NicModuleException(
                        NicModuleExceptionType.IFACENAMENULL,
                        "NetworkOSLinux:setInterfaceConfiguration called with null as interface IP:"
                        + ip + " GATEWAY:" + gateWay
                        + " DNS:" + dns
                        + " SUBNETMASK:" + subnetMask);

            }

            boolean result2 = false;
            StringBuffer cmd = new StringBuffer();
            cmd.append("ifconfig ");
            cmd.append(iPath);

            if ((ip != null) && !(ip.trim().equals(""))) {
                cmd.append(" inet ");
                cmd.append(ip);
            }
            if ((subnetMask != null) && !(subnetMask.trim().equals(""))) {
                cmd.append(" netmask ");
                cmd.append(subnetMask);
            }
            cmd.append(" up");


            TerminalApplicationExecutor executor =
                    new TerminalApplicationExecutor(cmd.toString(),
                    "");
            Integer exitVal = executor.runExec();

            String outputStr = executor.getOutputString();
            String errStr = executor.getErrorString();
            if ((exitVal == 0) && (gateWay != null)
                    && !(gateWay.trim().equals(""))) {
                result2 = setGateway(iPath,
                        gateWay,
                        subnetMask);

                if ((dns != null)
                        && !(dns.trim().equals(""))) {
                    if (result2) {
                        result2 = setDns(iPath,
                                dns);
                        return result2;
                    } else {
                        throw new NicModuleException(
                                NicModuleExceptionType.EXECUTIONERR,
                                "NetworkOSLinux:enableInterface execution error at setting Gateway"
                                + errStr);
                    }

                } else {
                    return result2;
                }

            } else {
                throw new NicModuleException(NicModuleExceptionType.EXECUTIONERR,
                        "NetworkOSLinux:enableInterface execution error at setting ip"
                        + errStr);
            }
        } catch (Exception ex) {
            throw new NicModuleException(NicModuleExceptionType.UNEXPLAINED,
                    "NetworkOSLinux:setInterfaceConfiguration exception "
                    + ex.getMessage());
        }
    }

    private boolean setToDhcp(String iPath) {
        try {

            if ((iPath == null) || (iPath.trim().equals(""))) {
                throw new NicModuleException(NicModuleExceptionType.EXECUTIONERR,
                        "NetworkOSLinux:setToDhcp called with null as interface:");
            }

            StringBuffer cmd = new StringBuffer();
            cmd.append("dhcpcd");
            cmd.append(" " + iPath + " -d -t 30");
            StringBuffer cmdDhcpStop = new StringBuffer();
            cmdDhcpStop.append("dhcpcd");
            cmdDhcpStop.append(" " + iPath + " -dk -t 30");

            String outputStr = "";
            String errStr = "";

            TerminalApplicationExecutor executor =
                    new TerminalApplicationExecutor(cmd.toString(),
                    "");

            TerminalApplicationExecutor executorDhcpKill =
                    new TerminalApplicationExecutor(cmdDhcpStop.toString(),
                    "");
            TerminalApplicationExecutor executorDhcpRenew =
                    new TerminalApplicationExecutor(cmd.toString(),
                    "");

            Integer exitVal = executor.runExec();

            outputStr = executor.getOutputString();
            errStr = executor.getErrorString();
            if (exitVal == 0) {
                return true;
            } else if (outputStr.contains(
                    "dhcpcd: already running") || errStr.contains(
                    "dhcpcd: already running")) {


                if (executorDhcpKill.runExec() == 0) {

                    Thread.sleep(1500);

                    if (executorDhcpRenew.runExec() != 0) {

                        throw new NicModuleException(
                                NicModuleExceptionType.EXECUTIONERR,
                                "NetworkOSLinux:setToDhcp execution error on DHCP renew...outputStr:"
                                + outputStr + " Error:"
                                + errStr + " Exit code:" + exitVal);
                    }

                } else {

                    throw new NicModuleException(
                            NicModuleExceptionType.EXECUTIONERR,
                            "NetworkOSLinux:setToDhcp execution error on DHCP release...outputStr:"
                            + outputStr + " Error:"
                            + errStr + " Exit code:" + exitVal);
                }

                return true;
            } else {
                throw new NicModuleException(NicModuleExceptionType.EXECUTIONERR,
                        "NetworkOSLinux:setToDhcp execution error...outputStr:"
                        + outputStr + " Error:"
                        + errStr + " Exit code:" + exitVal);

            }
        } catch (Exception ex) {
            throw new NicModuleException(NicModuleExceptionType.UNEXPLAINED,
                    "NetworkOSLinux:setToDhcp exception "
                    + ex.getMessage().toString());
        }
    }

    /**
     * renew dhcp client method
     * first tries to use dhcpcd if it's ok tries ifup
     * if dhcp fails tries dhclient
     * @param interface to be renewed in String form
     * @return true/false to represent succes or fail
     */
    public boolean renewDHCPClient(String iPath) {

        try {
            if ((iPath == null) || (iPath.trim().equals(""))) {
                throw new NicModuleException(
                        NicModuleExceptionType.IFACENAMENULL,
                        "NetworkOSLinux:setInterfaceConfiguration called with null as interface IP:");
            }
            boolean conti = false;
            StringBuffer cmd = new StringBuffer();
            cmd.append("dhcpcd -k");


            TerminalApplicationExecutor executor =
                    new TerminalApplicationExecutor(cmd.toString(),
                    "");
            Integer exitVal = executor.runExec();

            String outputStr = executor.getOutputString();
            String errStr = executor.getErrorString();
            if (exitVal == 0) {
                conti = true;
            } else {
                conti = false;
            }

            if (conti == true) {
                exitVal = -1;
                conti = false;
                cmd.delete(0,
                        cmd.length());
                cmd.append("ifup ");
                cmd.append(iPath);
                TerminalApplicationExecutor executor2 =
                        new TerminalApplicationExecutor(cmd.toString(),
                        "");
                exitVal = executor2.runExec();
                outputStr = executor2.getOutputString();
                errStr = executor2.getErrorString();

                if (exitVal == 0) {
                    conti = true;
                } else {
                    throw new NicModuleException(
                            NicModuleExceptionType.EXECUTIONERR,
                            "NetworkOSLinux:renewDHCPClient execution error on ifup part"
                            + errStr);
                }
            } else {

                exitVal = -1;
                conti = false;
                cmd.delete(0,
                        cmd.length());
                cmd.append("dhclient -r  ");
                cmd.append(iPath);
                TerminalApplicationExecutor executor3 =
                        new TerminalApplicationExecutor(cmd.toString(),
                        "");
                exitVal = executor3.runExec();
                outputStr = executor3.getOutputString();
                errStr = executor3.getErrorString();

                if (exitVal == 0) {
                    conti = true;
                } else {
                    throw new NicModuleException(
                            NicModuleExceptionType.EXECUTIONERR,
                            "NetworkOSLinux:renewDHCPClient execution error on dhclient -r part"
                            + errStr);
                }
                if (conti) {

                    exitVal = -1;
                    conti = false;
                    cmd.delete(0,
                            cmd.length());
                    cmd.append("dhclient ");
                    cmd.append(iPath);
                    TerminalApplicationExecutor executor4 =
                            new TerminalApplicationExecutor(cmd.toString(),
                            "");
                    exitVal = executor4.runExec();
                    outputStr = executor4.getOutputString();
                    errStr = executor4.getErrorString();

                    if (exitVal == 0) {
                        conti = true;
                    } else {
                        throw new NicModuleException(
                                NicModuleExceptionType.EXECUTIONERR,
                                "NetworkOSLinux:renewDHCPClient execution error on dhclient part"
                                + errStr);
                    }
                }
            }

            return conti;
        } catch (Exception ex) {
            throw new NicModuleException(NicModuleExceptionType.EXECUTIONERR,
                    "NetworkOSLinux:renewDHCPClient execution error on dhclient part"
                    + ex.getMessage());
        }
    }

    /**
     * set gateway method
     * executes route add and adds a default gw for interface and parses output
     * @param interface to be verified in String form
     * @param subnetMask value to be verified in String form
     * @return true/false to represent succes or fail
     */
    private boolean setGateway(String iPath,
            String gateWay,
            String subnetmask) {

        try {

            if ((iPath == null) || (iPath.trim().equals(""))) {
                throw new NicModuleException(
                        NicModuleExceptionType.IFACENAMENULL,
                        "NetworkOSLinux:setGateway called with null as interface IP:");
            }


            if ((gateWay == null) || (gateWay.trim().equals(""))) {
                throw new NicModuleException(
                        NicModuleExceptionType.IFACENAMENULL,
                        "NetworkOSLinux:setGateway called with null as gateway:");
            }


            StringBuffer cmd = new StringBuffer();
            cmd.append("route add -net default gw ");
            cmd.append(gateWay);
            cmd.append("\t");

            if ((subnetmask != null) && !(subnetmask.trim().equals(""))) {
                cmd.append(" netmask ");
                cmd.append(subnetmask);
            }


            cmd.append("\t dev ");
            cmd.append(iPath);

            TerminalApplicationExecutor executor =
                    new TerminalApplicationExecutor(cmd.toString(),
                    "");
            String defGwExistance[] = {"sh", "-c", "route -n | grep " + iPath
                + " | grep UG"
            };
            TerminalApplicationExecutor executor2 =
                    new TerminalApplicationExecutor(defGwExistance);
            Integer exitValCheck = executor2.runExec();

            String outputStrCh = executor2.getOutputString();
            String errStrCh = executor2.getErrorString();
            if (exitValCheck == 0) {

                String routeConfs[] = outputStrCh.split("\\s+");
                if (routeConfs.length > 0) // This means there is already a def gw 
                { // so we must delete it first

                    String deleteRoute = "route del -net "
                            + routeConfs[0] + " netmask " + routeConfs[2] + " "
                            + iPath;
                    TerminalApplicationExecutor executor3 =
                            new TerminalApplicationExecutor(deleteRoute);
                    Integer exitValDel = executor3.runExec();

                    String outputStrDel = executor3.getOutputString();
                    String errStrDel = executor3.getErrorString();

                    if (exitValDel != 0) {

                        throw new NicModuleException(
                                NicModuleExceptionType.EXECUTIONERR,
                                "NetworkOSLinux:setGateway cannot delete default gateway for "
                                + iPath
                                + errStrDel);

                    }


                }
                Integer exitVal = executor.runExec();

                String outputStr = executor.getOutputString();
                String errStr = executor.getErrorString();
                if (exitVal == 0) {
                    return true;
                } else {
                    throw new NicModuleException(
                            NicModuleExceptionType.EXECUTIONERR,
                            "NetworkOSLinux:setGateway "
                            + errStr);
                }

            } else {

                throw new NicModuleException(NicModuleExceptionType.EXECUTIONERR,
                        "NetworkOSLinux:setGateway cannot get default gateway info"
                        + errStrCh);
            }


        } catch (Exception ex) {
            throw new NicModuleException(NicModuleExceptionType.UNEXPLAINED,
                    "NetworkOSLinux:setGateway Exception "
                    + ex.getMessage());
        }


    }

    /**
     * set dns method
     * appends resolv.conf file the dns
     * @param interface to be verified in String form
     * @param dns value to be appended in String form
     * @return true/false to represent succes or fail
     */
    private boolean setDns(String iPath,
            String dns) {

        try {
            FileWriter fstream = new FileWriter("/etc/resolv.conf",
                    true);
            BufferedWriter out = new BufferedWriter(fstream);
            out.write("\nnameserver" + "\t" + dns);
            out.close();
            return true;
        } catch (IOException ex) {
            throw new NicModuleException(NicModuleExceptionType.UNEXPLAINED,
                    "NetworkOSLinux:setDns IOException "
                    + ex.getMessage());
        } catch (Exception ex) {
            throw new NicModuleException(NicModuleExceptionType.UNEXPLAINED,
                    "NetworkOSLinux:setDns Exception "
                    + ex.getMessage());
        }


    }

    private static boolean isIP(String hostAddress) {
        return hostAddress.split("[.]").length == 4;
    }


    public String getIp(String iPath) {
        try {
            NetworkInterface netface =  NetworkInterface.getByName(iPath);
            Enumeration addresses = netface.getInetAddresses();
            while (addresses.hasMoreElements()) {
                InetAddress ip = (InetAddress) addresses.nextElement();
                if (!ip.isLoopbackAddress() && isIP(ip.getHostAddress())) {
                    return ip.getHostAddress();
                }
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return null;
    }

    public String getDns(String iPath) {
        File name = new File("/etc/resolv.conf");
        String s[] = new String[2];
        try {
            if (name.isFile() && name.canRead()) {

                BufferedReader input = new BufferedReader(new FileReader(name));
                String text;
                while ((text = input.readLine().toLowerCase()) != null) {
                    s = text.split("nameserver ");
                    if (s.length == 2) {
                        return s[1];

                    }
                }


            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return null;

    }

    public String getGateway(String iPath) {
        try {
            String executionString[] = {"sh", "-c",
                "route -n | grep UG | grep " + iPath
            };


            TerminalApplicationExecutor executor =
                    new TerminalApplicationExecutor(executionString);
            Integer exitVal = executor.runExec();
            String strTmp1 = null, strTmp2 = null;
            String gwStrArr[];
            List<String> gwStr = new ArrayList<String>();
            String outputStr = executor.getOutputString();
            String errStr = executor.getErrorString();
            if (exitVal == 0) {

                String[] lines = outputStr.split("\n");
                for (int y = 0; y < lines.length; y++) {
                    String confList[] = lines[y].split("\\s+");
                    gwStr.add(confList[1]);
                }

                gwStrArr = gwStr.toArray(new String[gwStr.size()]);

            } else {
                throw new NicModuleException(NicModuleExceptionType.EXECUTIONERR,
                        "NetworkOSLinux:verifyGateway "
                        + errStr);
            }


            return gwStrArr[0];
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return null;
    }

    public String getSubnetMask(String iPath) {
        try {
            TerminalApplicationExecutor executor =
                    new TerminalApplicationExecutor("ifconfig",
                    iPath);
            Integer exitVal = executor.runExec();
            String strSubnetMask = null;
            String outputStr = executor.getOutputString();
            String errStr = executor.getErrorString();
            if (exitVal == 0) {
                Pattern pattern1 = Pattern.compile(
                        "Mask:[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}",
                        Pattern.CASE_INSENSITIVE
                        | Pattern.MULTILINE);
                Pattern pattern2 = Pattern.compile("Mask:");
                Matcher matcher1 = pattern1.matcher(outputStr);
                Matcher matcher2 = pattern2.matcher(outputStr);
                if (matcher1.find()) {
                    if (matcher2.find()) {
                        strSubnetMask = outputStr.substring(matcher2.end(),
                                matcher1.end());
                    }


                }
            } else {
                throw new NicModuleException(NicModuleExceptionType.EXECUTIONERR,
                        "NetworkOSLinux:verifySubnetMask execution error on ifconfig part"
                        + errStr);
            }

            return strSubnetMask;


        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return null;
    }

    public String getMacAddress(String iPath) {

        try {
            NetworkInterface nif = NetworkInterface.getByName(iPath);
            byte[] mac = nif.getHardwareAddress();
            StringBuffer sbMacAddr = new StringBuffer();
            sbMacAddr.append(String.format("%02X:%02X:%02X:%02X:%02X:%02X",
                    mac[0],
                    mac[1],
                    mac[2],
                    mac[3],
                    mac[4],
                    mac[5]));
            return sbMacAddr.toString();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return null;
    }

    public boolean isEnabled(String iPath) {
        try {
            TerminalApplicationExecutor executor =
                    new TerminalApplicationExecutor("ifconfig");
            executor.runExec();
            String outputStr = executor.getOutputString();
            if (outputStr.contains(iPath)) {
                return true;
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return false;

    }

    @Override
    public boolean isInterfaceExists(String iPath) {
        return true;
    }
}
